package com.ruoyi.data.controller;

import com.ruoyi.base.service.IRoomService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.data.domain.TdataRtRs;
import com.ruoyi.data.service.ITdataHtEqService;
import com.ruoyi.data.service.ITdataRtRsService;
import com.ruoyi.iot.IotContext;
import com.ruoyi.iot.WebTasksCallBack;
import com.ruoyi.iot.client.NioClient;
import com.ruoyi.iot.domain.CjqMeter;
import com.ruoyi.iot.domain.MeterCallStatus;
import com.ruoyi.iot.domain.vo.MeterCallStatusVo;
import com.ruoyi.param.domain.TparamTp;
import com.ruoyi.param.service.ITparamTpService;
import com.ruoyi.param.utils.TpTimeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/data/htrs")
@Api(tags = "工作状态")
@Slf4j
public class TdataRtRsController extends BaseController {

    @Value("${iot.webTimeOut}")
    private long webTimeOut;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private ITparamTpService tParamTpService;

    @Autowired
    private ITdataRtRsService tdataRtRsService;

    @Autowired
    private ITdataHtEqService tdataHtEqService;

    @Autowired
    private IotContext iotContext;

    /**
     * 查询工作状态列表
     */
    @GetMapping("/list")
    @ApiOperation("查询工作状态列表")
    public TableDataInfo<TdataRtRs> list(TdataRtRs tdataRtRs) {
        startPage();
        List<TdataRtRs> list = tdataRtRsService.selectRtRsList(tdataRtRs);
        return getDataTable(list);
    }

    /**
     * 恢复正常
     */
    @PreAuthorize("@ss.hasPermi('data:htrs:recover')")
    @GetMapping("/recover")
    @ApiOperation("恢复正常")
    public DeferredResult<AjaxResult> recover(@RequestParam("roomIds") List<String> roomIds) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }
        Map<String, List<TparamTp>> paramTpMapList = tParamTpService.selectTpListByRoomIds(roomIds, null).stream().collect(Collectors.groupingBy(TparamTp::getRoomId));
        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
            if (nioClient != null) {
                nioClient.writeElectrify(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                    @Override
                    public void callBack(boolean res) {
                        List<TparamTp> tparamTpList = paramTpMapList.getOrDefault(cjqMeter.getRoomId(), new ArrayList<>());
                        if (!tparamTpList.isEmpty() && tparamTpList.get(0) != null) {
                            TparamTp tparamTp = tparamTpList.get(0);
                            String[] time = TpTimeUtil.time(tparamTp);
                            if (!nioClient.writePeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(),
                                    Short.parseShort(time[2]), time[0], Short.parseShort(time[3]), time[1],
                                    new WebTasksCallBack(cjqMeter.getRoomId()) {
                                        @Override
                                        public void callBack(boolean res) {
                                            nioClient.readRelaysRealState(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                                                @Override
                                                public void callBack(boolean res) {
                                                    meterCallStatus.setStatus(res ? 0 : 1);
                                                    countDownLatch.countDown();
                                                    if (countDownLatch.getCount() == 0) {
                                                        deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                                    }
                                                }
                                            }.setTdataRtRsService(tdataRtRsService));
                                        }
                                    }.setTParamTpService(tParamTpService))
                            ) {
                                countDownLatch.countDown();
                            }
                        }
                    }
                }.setTdataRtRsService(tdataRtRsService).setTParamTpService(tParamTpService));
            } else {
                countDownLatch.countDown();
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }

    /**
     * 召测
     */
    @PreAuthorize("@ss.hasPermi('data:htrs:call')")
    @GetMapping("/call")
    @ApiOperation("召测")
    public DeferredResult<AjaxResult> call(@RequestParam("roomIds") List<String> roomIds) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }
        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
            if (nioClient != null) {
                nioClient.readRelaysRealState(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                    @Override
                    public void callBack(boolean res) {
                        nioClient.readTotalEnergy(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                            @Override
                            public void callBack(boolean res) {
                                log.info("call res " + res);
                                meterCallStatus.setStatus(res ? 0 : 1);
                                countDownLatch.countDown();
                                if (countDownLatch.getCount() == 0) {
                                    deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                }
                            }
                        }.setTdataRtRsService(tdataRtRsService));
                    }
                }.setTdataRtRsService(tdataRtRsService));
            } else {
                countDownLatch.countDown();
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }

    /**
     * 强制开机
     */
    @PreAuthorize("@ss.hasPermi('data:htrs:boot')")
    @GetMapping("/boot")
    @ApiOperation("强制开机")
    public DeferredResult<AjaxResult> boot(@RequestParam("roomIds") List<String> roomIds) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }
        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
            if (nioClient != null) {
                nioClient.writePeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                    @Override
                    public void callBack(boolean res) {
                        nioClient.writeElectrify(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                            @Override
                            public void callBack(boolean res) {
                                meterCallStatus.setStatus(res ? 0 : 1);
                                countDownLatch.countDown();
                                if (countDownLatch.getCount() == 0) {
                                    deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                }
                            }
                        }.setTdataRtRsService(tdataRtRsService).setTParamTpService(tParamTpService));
                    }
                });
            } else {
                countDownLatch.countDown();
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }

    /**
     * 强制关机
     */
    @PreAuthorize("@ss.hasPermi('data:htrs:shutdown')")
    @GetMapping("/shutdown")
    @ApiOperation("强制关机")
    public DeferredResult<AjaxResult> shutdown(@RequestParam("roomIds") List<String> roomIds) {

        List<MeterCallStatus> meterCallStatusList = new CopyOnWriteArrayList<>();
        MeterCallStatusVo meterCallStatusVo = new MeterCallStatusVo().setStatusList(meterCallStatusList);
        final DeferredResult<AjaxResult> deferredResult = new DeferredResult<>(webTimeOut);
        deferredResult.onTimeout(() -> deferredResult.setResult(AjaxResult.success(meterCallStatusVo)));

        List<CjqMeter> cjqMeterList = roomService.selectCjqMeterList(roomIds);
        if (cjqMeterList.isEmpty()) {
            deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
        }

        CountDownLatch countDownLatch = new CountDownLatch(roomIds.size());
        for (CjqMeter cjqMeter : cjqMeterList) {

            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(cjqMeter.getRoomId()).setStatus(1);
            meterCallStatusList.add(meterCallStatus);

            NioClient nioClient = iotContext.getNioClientMap().get(cjqMeter.getCjqNo());
            if (nioClient != null) {
                nioClient.writeOutage(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                    @Override
                    public void callBack(boolean res) {
                        nioClient.writePeriods(Integer.valueOf(cjqMeter.getMeterNo()).byteValue(), new WebTasksCallBack(cjqMeter.getRoomId()) {
                            @Override
                            public void callBack(boolean res) {
                                meterCallStatus.setStatus(res ? 0 : 1);
                                countDownLatch.countDown();
                                if (countDownLatch.getCount() == 0) {
                                    deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
                                }
                            }
                        });
                    }
                }.setTdataRtRsService(tdataRtRsService).setTParamTpService(tParamTpService));
            } else {
                countDownLatch.countDown();
            }
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
            roomIds.remove(cjqMeter.getRoomId());
        }

        for (String roomId : roomIds) {
            MeterCallStatus meterCallStatus = new MeterCallStatus().setRoomId(roomId).setStatus(1);
            meterCallStatusList.add(meterCallStatus);
            countDownLatch.countDown();
            if (countDownLatch.getCount() == 0) {
                deferredResult.setResult(AjaxResult.success(meterCallStatusVo));
            }
        }
        return deferredResult;
    }
}
